package com.slaffka.action;

import com.slaffka.dao.LoanDAO;
import com.slaffka.model.Loan;
import com.slaffka.model.Debtor;
import org.richfaces.component.SortOrder;

import javax.faces.bean.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.PersistenceContext;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 * User: slaffka
 * Date: 04.11.12
 * Time: 14:22
 * To change this template use File | Settings | File Templates.
 */
@ViewScoped
@Named("loanAction")
public class LoanAction extends AbstractAction implements Serializable{
    private static final int MAX_RESULT = 10;

    @PersistenceContext
    private EntityManager entityManager;

    @Inject
    private LoanDAO loanDAO;

    @Inject
    private UserSetting userSetting;

    private Loan loanModel = new Loan();

    private Debtor currentDebtor;
    private String currentDebtorStr;
    private LoanListSort loanListSort = new LoanListSort();
    private Loan currentLoan = new Loan();
    private List<Loan> loanList = null;

    public Loan getLoanModel() {
        return loanModel;
    }

    public Debtor getCurrentDebtor() {
        return currentDebtor;
    }

    public String getCurrentDebtorStr() {
        return currentDebtorStr;
    }

    public void setCurrentDebtorStr(String currentDebtorStr) {
        this.currentDebtorStr = currentDebtorStr;
    }

    public void setCurrentDebtor(Debtor currentDebtor) {
        this.currentDebtor = currentDebtor;
    }

    public List<Loan> getAllLoansForCurrentFilial(){
        return loanDAO.getAllLoansForCurrentFilial();
    }

    public List<String> autocomplete(String searchString){
        String[] searchWords = searchString.split(" ");
        String query = "select d from Debtor d ";
        if (searchWords.length > 0){
            query += " where lower(d.lastName) like '"  + searchWords[0].toLowerCase() + "%'";
            if (searchWords.length > 1){
                query += " and lower(d.firstName) like '" + searchWords[1].toLowerCase() + "%'";
                if (searchWords.length > 2){
                    query += " and lower(d.middleName) like '" + searchWords[2].toLowerCase() + "%'";
                }
            }
        }

        List<String> FIODebtorList = new ArrayList<String>();
        List<Debtor> debtorList = entityManager
                .createQuery(query)
                .setMaxResults(MAX_RESULT)
                .getResultList();
        for (Debtor debtor: debtorList){
            FIODebtorList.add(debtor.getLastName() + " " + debtor.getFirstName() + " " + debtor.getMiddleName());
        }
        return FIODebtorList;
    }

    public void addNewLoan(){
        if (loanModel != null){
            Debtor debtor = getDebtorByCurrDebtorStr();
            if (debtor != null){
                try {
                    loanModel.setCreateDate(new Date());
                    loanModel.setDebtor(debtor);
                    loanModel.setFilial(userSetting.getCurrentUser().getFilial());
                    loanModel.setOwner(userSetting.getCurrentUser());
                    loanDAO.addNewLoan(loanModel);
                    resetLoanModel();
                    msg = "операция заключения договора о займе выполнилась успешно";
                    printInfo();
                }
                catch (Exception e){
                    msg = "Операция заключения договора о займе выполнилась с ошибкой";
                    printError(e);
                }
            }
        }
    }

    private Debtor getDebtorByCurrDebtorStr() {
        Debtor debtor = null;
        try {
            String[] searchWords = currentDebtorStr.split(" ");
            String query = "select d from Debtor d ";
            if (searchWords.length > 0){
                query += " where lower(d.lastName) = '"  + searchWords[0].toLowerCase() + "'";
                if (searchWords.length > 1){
                    query += " and lower(d.firstName) = '" + searchWords[1].toLowerCase() + "'";
                    if (searchWords.length > 2){
                        query += " and lower(d.middleName) = '" + searchWords[2].toLowerCase() + "'";
                    }
                }
            }
            debtor = (Debtor) entityManager
                    .createQuery(query)
                    .getSingleResult();

        } catch (NullPointerException e){
            msg = "не найден заемщик (пустая строка)";
            e.printStackTrace();
        } catch (NoResultException e){
            msg = "не найден заемщик " + currentDebtorStr;
            printError(e);
        } catch (NonUniqueResultException e){
            msg = "найдено более одного заемщика " + currentDebtorStr;
            printError(e);
        } catch (Exception e){
            msg = "Операция заключения договора о займе выполнилась с ошибкой";
            printError(e);
        }
        return debtor;
    }

    public void finishLoan(Loan loan){
        if (loan != null){
            try {
                loanDAO.finishLoan(loan);
                resetLoanModel();
                msg = "Операция завершения договора о займе прошла успешно";
                printInfo();
            } catch (Exception e){
                msg = "Ошибка операции завершения договора о займе";
            }
        }
    }

    public void removeLoan(Loan loan){
        if (loan != null){
            try {
                entityManager.refresh(loan);
                entityManager.remove(loan);
                entityManager.flush();
                resetLoanModel();
                msg = "Операция удаления займ успешно завершена";
                printInfo();
            } catch (Exception e){
                msg = "Ошибка операции удаления займа";
                printError(e);
            }
        }
    }

    private void resetLoanModel() {
        currentDebtorStr = "";
        loanModel = new Loan();
        currentLoan = new Loan();
        loanList = null;
    }

    public void repay(){

    }


    public void updateCurrentLoan(){
        if (currentLoan != null){
            Debtor debtor = getDebtorByCurrDebtorStr();
            if (debtor != null){
                try {
                    currentLoan.setDebtor(debtor);
                    loanModel.setOwner(userSetting.getCurrentUser());
                    entityManager.merge(currentLoan);
                    entityManager.flush();
                    resetLoanModel();
                    msg = "Операция обновления информации о займе выполнилась успешно";
                    printInfo();
                } catch (Exception e){
                    msg = "Операция обновления информации о займе выполнилась с ошибкой";
                    printError(e);
                }
            }
        }
    }

    public void setCurrentLoan(Loan currentLoan){
        this.currentLoan = currentLoan;
        this.currentDebtorStr = currentLoan.getDebtor().getFIO();
    }

    public Loan getCurrentLoan() {
        return currentLoan;
    }

    public void setLoanListSort(LoanListSort loanListSort) {
        this.loanListSort = loanListSort;
    }

    public LoanListSort getLoanListSort() {
        return loanListSort;
    }

    public Loan getTotalLoan(){
        double totalAmount = 0D;
        for (Loan loan: getLoanList()){
            totalAmount += loan.getAmount();
        }
        Loan totalLoan = new Loan();
        totalLoan.setAmount(totalAmount);

        return totalLoan;
    }

    public List<Loan> getLoanList() {
        if (loanList == null){
            loanList = loanDAO.getLoanList();
        }
        return loanList;
    }

    public class LoanListSort implements Serializable{
        private SortOrder amountOrder = SortOrder.unsorted;
        private SortOrder createDateOrder = SortOrder.unsorted;
        private SortOrder debtorOrder = SortOrder.unsorted;
        private SortOrder periodOrder = SortOrder.unsorted;
        private SortOrder plannedDateOrder = SortOrder.unsorted;
        private SortOrder plannedAmountOrder = SortOrder.unsorted;
        private SortOrder overdueDaysOrder = SortOrder.unsorted;
        private SortOrder currentAmountOrder = SortOrder.unsorted;
        private SortOrder feeForUseOfFundsOrder = SortOrder.unsorted;
        private SortOrder factFeeForUseOfFundsOrder = SortOrder.unsorted;
        private SortOrder filialOrder = SortOrder.unsorted;

        public void sortByAmount(){
            createDateOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (amountOrder.equals(SortOrder.ascending)){
                amountOrder = SortOrder.descending;
            } else {
                amountOrder = SortOrder.ascending;
            }
        }

        public void sortByCreateDate(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (createDateOrder.equals(SortOrder.ascending)){
                createDateOrder = SortOrder.descending;
            } else {
                createDateOrder = SortOrder.ascending;
            }
        }

        public void sortByDebtor(){
            amountOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (debtorOrder.equals(SortOrder.ascending)){
                debtorOrder = SortOrder.descending;
            } else {
                debtorOrder = SortOrder.ascending;
            }
        }

        public void sortByPeriod(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (periodOrder.equals(SortOrder.ascending)){
                periodOrder = SortOrder.descending;
            } else {
                periodOrder = SortOrder.ascending;
            }
        }

        public void sortByPlannedDate(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (plannedDateOrder.equals(SortOrder.ascending)){
                plannedDateOrder = SortOrder.descending;
            } else {
                plannedDateOrder = SortOrder.ascending;
            }
        }

        public void sortByPlannedAmount(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (plannedAmountOrder.equals(SortOrder.ascending)){
                plannedAmountOrder = SortOrder.descending;
            } else {
                plannedAmountOrder = SortOrder.ascending;
            }
        }

        public void sortByOverdueDays(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (overdueDaysOrder.equals(SortOrder.ascending)){
                overdueDaysOrder = SortOrder.descending;
            } else {
                overdueDaysOrder = SortOrder.ascending;
            }
        }

        public void sortByCurrentAmount(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (currentAmountOrder.equals(SortOrder.ascending)){
                currentAmountOrder = SortOrder.descending;
            } else {
                currentAmountOrder = SortOrder.ascending;
            }
        }

        public void sortByFeeForUseOfFunds(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (feeForUseOfFundsOrder.equals(SortOrder.ascending)){
                feeForUseOfFundsOrder = SortOrder.descending;
            } else {
                feeForUseOfFundsOrder = SortOrder.ascending;
            }
        }

        public void sortByFactFeeForUseOfFunds(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            filialOrder = SortOrder.unsorted;
            if (factFeeForUseOfFundsOrder.equals(SortOrder.ascending)){
                factFeeForUseOfFundsOrder = SortOrder.descending;
            } else {
                factFeeForUseOfFundsOrder = SortOrder.ascending;
            }
        }

        public void sortByFilial(){
            amountOrder = SortOrder.unsorted;
            debtorOrder = SortOrder.unsorted;
            createDateOrder = SortOrder.unsorted;
            plannedDateOrder = SortOrder.unsorted;
            periodOrder = SortOrder.unsorted;
            overdueDaysOrder = SortOrder.unsorted;
            plannedAmountOrder = SortOrder.unsorted;
            feeForUseOfFundsOrder = SortOrder.unsorted;
            currentAmountOrder = SortOrder.unsorted;
            factFeeForUseOfFundsOrder = SortOrder.unsorted;
            if (filialOrder.equals(SortOrder.ascending)){
                filialOrder = SortOrder.descending;
            } else {
                filialOrder = SortOrder.ascending;
            }
        }

        public SortOrder getAmountOrder() {
            return amountOrder;
        }

        public void setAmountOrder(SortOrder amountOrder) {
            this.amountOrder = amountOrder;
        }

        public SortOrder getCreateDateOrder() {
            return createDateOrder;
        }

        public void setCreateDateOrder(SortOrder createDateOrder) {
            this.createDateOrder = createDateOrder;
        }

        public SortOrder getDebtorOrder() {
            return debtorOrder;
        }

        public void setDebtorOrder(SortOrder debtorOrder) {
            this.debtorOrder = debtorOrder;
        }

        public SortOrder getPeriodOrder() {
            return periodOrder;
        }

        public void setPeriodOrder(SortOrder periodOrder) {
            this.periodOrder = periodOrder;
        }

        public SortOrder getPlannedDateOrder() {
            return plannedDateOrder;
        }

        public void setPlannedDateOrder(SortOrder plannedDateOrder) {
            this.plannedDateOrder = plannedDateOrder;
        }

        public SortOrder getPlannedAmountOrder() {
            return plannedAmountOrder;
        }

        public void setPlannedAmountOrder(SortOrder plannedAmountOrder) {
            this.plannedAmountOrder = plannedAmountOrder;
        }

        public SortOrder getOverdueDaysOrder() {
            return overdueDaysOrder;
        }

        public void setOverdueDaysOrder(SortOrder overdueDaysOrder) {
            this.overdueDaysOrder = overdueDaysOrder;
        }

        public SortOrder getCurrentAmountOrder() {
            return currentAmountOrder;
        }

        public void setCurrentAmountOrder(SortOrder currentAmountOrder) {
            this.currentAmountOrder = currentAmountOrder;
        }

        public SortOrder getFeeForUseOfFundsOrder() {
            return feeForUseOfFundsOrder;
        }

        public void setFeeForUseOfFundsOrder(SortOrder feeForUseOfFundsOrder) {
            this.feeForUseOfFundsOrder = feeForUseOfFundsOrder;
        }

        public SortOrder getFactFeeForUseOfFundsOrder() {
            return factFeeForUseOfFundsOrder;
        }

        public void setFactFeeForUseOfFundsOrder(SortOrder factFeeForUseOfFundsOrder) {
            this.factFeeForUseOfFundsOrder = factFeeForUseOfFundsOrder;
        }

        public SortOrder getFilialOrder() {
            return filialOrder;
        }

        public void setFilialOrder(SortOrder filialOrder) {
            this.filialOrder = filialOrder;
        }
    }
}
